package _剑指offer._设计模式._单例模式;

/**
 * 单例模式的三种类型
 * 饿汉式：在类加载的时候就初始化好一个实例
 *      特点：
 *          构造器私有，防止 new 出新的实例
 *          使用 private static final 定义实例变量并初始化，static是类共享且唯一，final防止修改
 *      缺点：如果实例很占内存，可能会浪费空间
 * 懒汉式：在调用时在生成实例
 * 
 * 恶汉和懒汉都是单线程下没问题，多线程下有问题；多线程下使用 双重校验锁 dcl 是最好的
 * 
 * 双重校验锁：
 *      特点：
 *          变量加 volatile 防止jvm指令重拍
 *          双重校验 提高性能；不能直接锁整个方法，粒度太大
 *      
 *          
 */
class Hungry {
    private Hungry(){}
    private static final Hungry HUNGRY = new Hungry();
    public static Hungry getInstance() {
        return HUNGRY;
    }
}

class Lazy {
    private Lazy() {
        System.out.println(Thread.currentThread().getName() + " ok");
    }
    private static Lazy LAZY;
    public static Lazy getInstance() {
        if (LAZY == null) {
            LAZY = new Lazy();
        }
        return LAZY;
    }
    
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                Lazy.getInstance();
            }).start();
        }
    }
}

class LazyDcl {
    private LazyDcl() {
        System.out.println(Thread.currentThread().getName() + " ok");
    }
    private static volatile LazyDcl LAZYDCL;
    public static LazyDcl getInstance() {
        if (LAZYDCL == null) {
            synchronized (LazyDcl.class) {
                if (LAZYDCL == null) {
                    LAZYDCL = new LazyDcl();
                }
            }
        }
        return LAZYDCL;
    }
    
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                LazyDcl.getInstance();
            }).start();
        }
    }
}

// 懒汉式 dcl
class Single {
    private Single() {}
    private static volatile Single single;
    public static Single getInstance() {
        if (single == null) {
            synchronized (Single.class) {
                if (single == null) {
                    single = new Single();
                }
            }
        }
        return single;
    }
}